4.3 返回值

有返回值的函数,必须有明确的return终止语句。

func test(x int)int{ 
   if x>0{ 
       return 1
    }else if x<0{ 
       return -1
    } 
}                // 错误:missing return at end of function
 

除非有panic,或者无break的死循环,则无须return终止语句。

func test(x int)int{ 
   for{ 
       break
    } 
}                // 错误:missing return at end of function

借鉴自动态语言的多返回值模式,函数得以返回更多状态,尤其是error模式。

import"errors" 
  
func div(x,y int) (int,error) { // 多返回值列表必须使用括号 
   if y==0{ 
       return 0,errors.New("division by zero") 
    } 
  
   return x/y,nil
}

稍有不便的是没有元组(tuple)类型,也不能用数组、切片接收,但可用“_”忽略掉不想要的返回值。多返回值可用作其他函数调用实参,或当作结果直接返回。

func div(x,y int) (int,error) { 
   if y==0{ 
       return 0,errors.New("division by zero") 
    } 
  
   return x/y,nil
} 
  
func log(x int,err error) { 
   fmt.Println(x,err) 
} 
  
func test() (int,error) { 
   return div(5,0)         // 多返回值用作return结果 
} 
  
func main() { 
   log(test())          // 多返回值用作实参 
}
 

命名返回值

对返回值命名和简短变量定义一样,优缺点共存。

func paging(sql string,index int) (count int,pages int,err error) { 
}

从这个简单的示例可看出,命名返回值让函数声明更加清晰,同时也会改善帮助文档和代码编辑器提示。

命名返回值和参数一样,可当作函数局部变量使用,最后由return隐式返回。

func div(x,y int) (z int,err error) { 
   if y==0{ 
       err=errors.New("division by zero") 
       return
    } 
  
   z=x/y
   return         // 相当于 "return z,err" 
}

这些特殊的“局部变量”会被不同层级的同名变量遮蔽。好在编译器能检查到此类状况,只要改为显式return返回即可。

func add(x,y int) (z int) { 
    { 
       z:=x+y       // 新定义的同名局部变量,同名遮蔽 
       return       // 错误:z is shadowed during return(改成 "return z" 即可) 
    } 
  
   return
}

除遮蔽外,我们还必须对全部返回值命名,否则编译器会搞不清状况。

func test() (int,s string,e error) { 
   return 0, "",nil        // 错误:cannot use 0(type int)as type string in return argument
}

显然编译器在处理return语句的时候,会跳过未命名返回值,无法准确匹配。

如果返回值类型能明确表明其含义,就尽量不要对其命名。

func NewUser() (*User,error)